#include "SlackList.h"

// Lo status è status.val (intero) e status.msg (stringa), l'intero può essere
//Message=1
//Warning=2 (message to log)
//Error=3 (error to log)
//Fatal=4 (fatal + log)
//Stop packet loading on negative number

SlackList::SlackList() {

  packpath="/var/log/packages";
  index=0;
  conf.delay=10;
  char stattmp[1024];

  pkglist=LsDir(packpath);
  filesn=pkglist.size();

  if(filesn==0) {
    status.lev=4;
    status.msg="No package directory founded in " + packpath + " path.";
  }
  else {
    if (packpath[packpath.size()]!='/') packpath.append("/");
    snprintf(stattmp,1024,"Loaded %i package files in %s directory.",pkglist.size(),packpath.c_str());
    status.lev=0;
    status.msg=stattmp;
  }

}

SlackList::~SlackList() {

  //Deallocare tto
  //int i;
  //for(i=0;i<pkglist.size();i++) { delete &pkglist[i]; }

  //delete [ ] pkglist;

}

Pkg SlackList::GetAPkg() {

  Pkg currp;
  string s,s2;

  string field;
  string cont;

  size_t pos;
  char first;

  vector <string> stndrd;

  string complpath = packpath + pkglist[index];
  index++;

  stringstream sstat;

  try {
    fs.open(complpath.c_str());
  }
  catch (exception &x) {
    status.lev=3;
    sstat << "[#" << index << "] Error opening " << complpath << " package file.";
    status.msg=sstat.str();

    return currp;
  }

  while(getline(fs,s)) {

    if(s2!="") s=s2;

    first=s.c_str()[0];

    pos=s.find_first_of(":");
    if (pos==s.npos) {
      cout << "Error: bad line in package file " + complpath + "(" + s + ")" << endl;
      continue;
    }


    field=s.substr(0,pos);
    cont=s.substr(pos+1,s.length());
    s2="";

    // !isupper FALSO isupper VERO

    // "FIELD: content"
    if (isupper(first) && s.length()>pos+1)  {
      FillFields(field,cont,&currp);
    }

    // "FIELD:"
    else if (isupper(first) && cont.length()==0)  {

      while(getline(fs,s2)) {
	  first=s2.c_str()[0];
	  //after the DESCRIPTION filed usually there is only FILE LIST field.. this seems works
	  if(s2.compare(0,10,"FILE LIST:")) {
	    cont+='\n';
	    cont+=s2;
	  }
	  else {
	    break;
	  }

      }
      FillFields(field,cont,&currp);
    }
    else {
      cout << "Error: bad line in package file " + complpath + "(" + s + ")" << endl;
    }
  }

  //dovrebbe anche chekkare se la lista dei file e' vuota? forse no, per completezza dell'intero sistema di pacchetti caricato
  if(currp.GetField("Package")=="") {
    currp.enabled=false;

    if(index==filesn) {
      status.lev=-2;
      sstat << "[#" << index << "] Error loading last package file (" << complpath << ").";
      status.msg=sstat.str();

    }
    else {
      status.lev=2;
      sstat << "[#" << index << "] Error loading package file (" << complpath << ").";
      status.msg=sstat.str();

    }
  }
  else {
    if(index==filesn) {
      status.lev=-1;
      sstat << "[#" << index << "] Last package " << currp.GetField("Package") << " loaded.";
      status.msg=sstat.str();

    }
    else {
      status.lev=1;

      sstat << "[#" << index << "] Package " << currp.GetField("Package") << " loaded.";
      status.msg=sstat.str();

    }
    currp.enabled=true;
  }

  fs.close();
  return currp;

}

void SlackList::FillFields(string f, string c, Pkg *pk) {

  unsigned int i, cutAt,ret;
  vector <string> stndrd = standardize(f,c);
  string str;

  for(i=0;i<stndrd.size();i=i+2) {


  // PROCESSING FILE LIST
    if(!stndrd[i].compare("flist")) {

      str=stndrd[i+1];

      while( (cutAt = str.find_first_of('\n')) != str.npos ) {
	if(cutAt > 0) {

	  ret=checkFile(str.substr(0,cutAt).c_str());
	  //if(ret!='F') 
	  pk->SetFile(str.substr(0,cutAt),ret);
	}
	str = str.substr(cutAt+1);
      }
      if(str.length() > 0) {

	  ret=checkFile(str.c_str());
	  //if(ret!='X') 
	  pk->SetFile(str,ret);
      }

    }
    else pk->SetField(stndrd[i],stndrd[i+1]);
  }
}


string cleandescr(const std::string &s) {

    string sub,toret; 
    int i;
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, '\n')) {

      i = item.find_first_of(":"); i++;
      sub=item.substr(i,item.npos);

      if((i!=item.npos)&&sub.length()>0) toret=toret + sub + "\n";

    }
    return toret;
}


vector <string> SlackList::standardize(string f, string c) {

  vector <string> ret;

  unsigned int i;
  // clear contents starting with white spaces
  for(i=0;i<c.length();i++) {
    if(c.c_str()[i]!=' ') { break; }
  }
  c=c.substr(i);

  if(!f.compare("PACKAGE NAME")) {

      string nm=c;
      string ver="";
      unsigned int n, num_sep=0;

      //cut name and version 
      for(n=0;n<c.size();n++) {
	if(c[n]=='-') { num_sep++; } 
      }
      //name-name-version format
      if(num_sep>0 && num_sep<3) {
	if(((n=c.find_last_of('-'))!=c.npos) && isdigit(c[n+1])) {
	  nm=c.substr(0, n);
	  ver=c.substr(n+1,c.size());
	}
      }
      //name-version-architecture-build
      else {
	num_sep=0;
	for(n=c.size();n>0;n--) {
	  if(c[n]=='-') {
	    num_sep++; 
	    if(num_sep==3) { 
	      nm=c.substr(0, n);
	      ver=c.substr(n+1,c.size());
	    }
	  }
	}
      }
// nel caso di pacchetti col nome guasto, dovrebbe mettere un qlcsa del genere (qsto nn fa)
//       else {
// 	nm=c;
// 	ver="";
//       }

      ret.push_back(string("Package-RealName"));
      ret.push_back(c);

      ret.push_back(string("Package"));
      ret.push_back(nm);

//      if(!ver.empty()) {
	ret.push_back(string("Version"));
	ret.push_back(ver);
//      }
      return ret;
  }
  else if(!f.compare("UNCOMPRESSED PACKAGE SIZE")) {
      unsigned int pos;
      char tmpret[128], tmpc[128];
      int m=0;
      long sz;

      // keep only digits and clean the end of string
      for(i=0;i<128;i++) {
	if(i>c.length()) tmpc[m]='\0';
	else if(isdigit(c.c_str()[i])) { tmpc[m]=c[i]; m++; }
      }
      c=tmpc;

      ret.push_back(string("Installed-Size"));

      if((pos=c.find_first_of('K')) != c.npos) {
	ret.push_back(c.substr(0,pos));
      }
      else if((pos=c.find_first_of('M')) != c.npos) {
	sz=atoi(c.substr(0,pos).c_str())*1024;
	snprintf(tmpret,128,"%ld",sz);
	ret.push_back(tmpret);
      }
      else if((pos=c.find_first_of('G')) != c.npos) { 
	sz=atoi(c.substr(0,pos).c_str())*1048576; //1024*1024
	snprintf(tmpret,128,"%ld",sz);
	ret.push_back(tmpret);
      }
      else ret.push_back(c);
      return ret;
  }
  else if(!f.compare("PACKAGE DESCRIPTION")) {
      ret.push_back(string("Description"));
      ret.push_back(cleandescr(c));
   
      return ret;
  }
  else if(!f.compare("FILE LIST")) {
      ret.push_back(string("flist"));

      // add root directory if missing
      unsigned int i;
      string newc;
      for(i=0;i<c.length();i++) {
	if(c[i]=='\n' && c[i+1]!='/') { newc+="\n/"; }
	else newc+=c[i];
      }
      ret.push_back(newc);
      return ret;
  }
  ret.push_back(f);ret.push_back(c);
  return ret;

}

vector <string> SlackList::LsDir (string dir)
{

    vector<string> list;

    DIR *dp;
    struct dirent *dirp;
    string complpath;
    char ret;

    if(dir[dir.size()-1]!='/') dir.append("/");

    if((dp  = opendir(dir.c_str())) == NULL) {
	return list;
    }

    while ((dirp = readdir(dp)) != NULL) {

	  complpath=dir + string(dirp->d_name);

	  ret=checkFile(complpath.c_str());
	  if(ret=='Y') {
	    list.push_back(string(dirp->d_name));
	  }
    }
    closedir(dp);
    return list;
}


bool SlackList::isInstalled(string str) {
	
	bool ret;
	string complpath=packpath + str;

	ret=checkFile(complpath.c_str());
  	if(ret=='Y') {
	    return true;
	}
	return false;
}